package com.markhsiu.nio.proxy;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class ProxyAcceptorTask extends Thread{

	private ProxyBean bean;
	private Selector selector;
	 
	
	public ProxyAcceptorTask(ProxyBean proxyBean) {
		super("ProxyAcceptorTask");
		this.bean = proxyBean;
		try {
			selector = Selector.open();
			ServerSocketChannel serverChannel = ServerSocketChannel.open();
			serverChannel.configureBlocking(false);
			serverChannel.socket().bind(new InetSocketAddress(bean.local_ip,bean.local_port));
			
			serverChannel.register(selector, SelectionKey.OP_ACCEPT);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void run() {
	  while(!Thread.currentThread().isInterrupted()){
		  try {
			  
			int count = selector.select(100);
			if(count == 0){
				continue;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		  
		  Set<SelectionKey> keys = selector.selectedKeys();
		  Iterator<SelectionKey> iterator = keys.iterator();
		  while(iterator.hasNext()){
			  SelectionKey key = iterator.next();
			  if(!key.isValid()){
				  continue;
			  }
			  
			  if(key.isAcceptable()){
				  try {
					System.out.println("doAccept ... ");
					doAccept(key);
				} catch (IOException e) {
					e.printStackTrace();
				}
			  } else {
				 System.out.println("do work ... ");
				 ProxySession session = (ProxySession) key.attachment();
				 try {
					session.handler.execute(session, key);
				} catch (IOException e) {
					e.printStackTrace();
				}
			  }
			  iterator.remove();
		  }
	  }
	}
	
	
	
	public void doAccept(SelectionKey key) throws IOException{
		ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
		SocketChannel frontChannel = serverChannel.accept();
		//可以设置 SocketChannel 为非阻塞模式（non-blocking mode）.设置之后，
		//就可以在异步模式下调用connect(), read() 和write()了。
		frontChannel.configureBlocking(false);
		SocketChannel backendChannel = initRemote();
		
		ProxySession session = new ProxySession();
		session.selector = selector;
		session.frontChannel = frontChannel;
		session.backendChannel = backendChannel;
		frontChannel.register(selector, SelectionKey.OP_READ, session);
		backendChannel.register(selector, SelectionKey.OP_READ, session);
	}
	
	private  SocketChannel initRemote() throws IOException{
		 
		SocketChannel channel = SocketChannel.open();
		channel.connect(new InetSocketAddress(bean.remote_ip, bean.remote_port));
		//顺序很关键，必须在连接后设置为为阻塞模式
		channel.configureBlocking(false);
		return channel;
	}
	
	
	 public  void close() {}
}
